import { v2, Vec2 } from 'cc';
import { AStarNode } from './AStarNode';
import { EventTarget } from 'cc';

export class AStarWay {
    target: Vec2;
    start: Vec2;
    map: number[][];//1可以走2不可以走
    closedList: AStarNode[] = [];//已经走过的路径
    openList: AStarNode[] = [];//需要计算的路径
    nowNode: AStarNode;  //当前路径
    private eventTarget: EventTarget;

    //路径计算值
    pathCalValue = [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [-1, -1], [1, -1], [-1, 1]];

    constructor(start: Vec2, target: Vec2, map: number[][], eventTarget: EventTarget) {
        this.start = start;
        this.target = target;
        this.map = map;
        this.nowNode = new AStarNode(start.x, start.y);
        this.openList.push(this.nowNode);
        this.eventTarget = eventTarget;
    }

    /**
     * 获取路径
     * @returns 
     */
    async getPath(): Promise<Vec2[]> {
        // let currentNode = this.closedList[0];
        // this.eventTarget.emit('r0', currentNode);

        // this.openList = this.getNeighbors(currentNode);

        // this.eventTarget.emit('r1', this.openList);
        await this.Sleep(1000);
        while (this.openList.length > 0) {

            let currentNode = this.openList[0];
            let currentIndex = 0;

            for (let i = 1; i < this.openList.length; i++) {
                if (this.openList[i].f < currentNode.f) {
                    currentNode = this.openList[i];
                    currentIndex = i;
                }
            }

            if (currentNode.x == this.target.x && currentNode.y == this.target.y) {
                console.log("到达终点");
            }

            this.openList.splice(currentIndex, 1);
            this.closedList.push(currentNode);

            this.eventTarget.emit('r0', currentNode);
            await this.Sleep(10);

            var neighbors = this.getNeighbors(currentNode);
            for (let i = 0; i < neighbors.length; i++) {
                if (this.closedList.find(s => s.x == neighbors[i].x && s.y == neighbors[i].y)) continue;  //在关闭列表中,跳过

                if (!this.openList.find(s => s.x == neighbors[i].x && s.y == neighbors[i].y)) {
                    neighbors[i].parent = currentNode;
                    this.openList.push(neighbors[i]);

                    this.eventTarget.emit('r1', neighbors[i]);
                    await this.Sleep(10);

                    if (neighbors[i].x == this.target.x && neighbors[i].y == this.target.y) {
                        console.log("到达终点");

                        const resultNode = new Array<AStarNode>();
                        resultNode.push(neighbors[i])
                        while (currentNode !== null) {
                            resultNode.push(currentNode);
                            currentNode = currentNode.parent;
                        }

                        this.eventTarget.emit('result', resultNode);
                        await this.Sleep(10);
                        return [];
                    }
                } else if (currentNode.g + 10 < neighbors[i].g) {
                    neighbors[i].parent = currentNode;
                }
            }
        }

        return [];
    }

    getNeighbors(node: AStarNode): AStarNode[] {
        var neighbors = new Array<AStarNode>();
        this.pathCalValue.forEach(i => {
            var path = v2(i[0] + node.x, i[1] + node.y);
            if (path.x >= 0 && path.y >= 0 && path.y < this.map.length && path.x < this.map[0].length) {
                if (this.map[path.y][path.x] == 0) {
                    var g = (Math.abs(path.x) == 1 && Math.abs(path.y) ? 14 : 10) + node.g;
                    var h = (Math.abs(this.target.x - path.x) + Math.abs(this.target.y - path.y)) * 10;
                    var aStarNode = new AStarNode(path.x, path.y);
                    aStarNode.g = g;
                    aStarNode.h = h;
                    aStarNode.f = g + h;
                    neighbors.push(aStarNode);
                }
            }
        });

        return neighbors;
    }

    // getBest() {
    //     //对needCalNode进行从小到大排序
    //     this.needCalNode = this.needCalNode.sort((n1, n2) => {
    //         return n1.f - n2.f
    //     });

    //     this.nowPath =  this.needCalNode[0]
    //     this.finishedNode.push(this.nowPath);
    //     this.needCalNode=[];
    // }

    Sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}


